package com.investment.dcf;

import java.util.Scanner;
import java.text.DecimalFormat;
import java.util.stream.IntStream;

/**
 * DCF模型计算器 - 用于计算企业内在价值
 */
public class DCFCalculator {

  public static void main(String[] args) {
    // 使用彩色标题
    System.out.println(BOLD + CYAN + "\n===== DCF模型企业内在价值计算器 =====" + RESET);

    // 获取用户输入的参数
    DCFParameters params = getUserInput();

    // 获取初始自由现金流
    double initialFCF = getInitialFreeCashFlow();

    // 计算DCF估值
    DCFValuation valuation = calculateDCFValuation(initialFCF, params);

    // 生成估值报告
    generateValuationReport(valuation, params);
  }

  /**
   * 获取用户输入的DCF参数
   */
  private static DCFParameters getUserInput() {
    Scanner scanner = new Scanner(System.in);
    DCFParameters params = new DCFParameters();

    // 打印参数输入标题
    System.out.println(YELLOW + BOLD + "\n【参数输入】" + RESET);
    System.out.println(YELLOW + "+-----------------------------------------------+" + RESET);

    // 折现率输入
    System.out.print(YELLOW + "| " + RESET + CYAN + "请输入折现率(WACC)" + RESET + "，例如8表示8%: ");
    double rate = scanner.nextDouble();
    // 将百分比转换为小数形式（如8转为0.08）
    params.setDiscountRate(rate / 100);

    // 短期增长率输入
    System.out.print(YELLOW + "| " + RESET + CYAN + "请输入短期增长率" + RESET + "，例如5表示5%: ");
    rate = scanner.nextDouble();
    // 将百分比转换为小数形式（如5转为0.05）
    params.setGrowthRate(rate / 100);

    // 永续增长率输入
    System.out.print(YELLOW + "| " + RESET + CYAN + "请输入永续增长率" + RESET + "，例如2表示2%: ");
    rate = scanner.nextDouble();
    // 将百分比转换为小数形式（如2转为0.02）
    params.setTerminalGrowthRate(rate / 100);

    // 预测年数输入
    System.out.print(YELLOW + "| " + RESET + CYAN + "请输入预测年数" + RESET + "(5-10年): ");
    int years = scanner.nextInt();
    if (years < 5)
      years = 5;
    if (years > 10)
      years = 10;
    params.setForecastYears(years);

    System.out.println(YELLOW + "+-----------------------------------------------+" + RESET);

    return params;
  }

  /**
   * 获取初始自由现金流
   */
  private static double getInitialFreeCashFlow() {
    Scanner scanner = new Scanner(System.in);

    // 打印初始现金流输入标题
    System.out.println(GREEN + BOLD + "\n【初始现金流输入】" + RESET);
    System.out.println(GREEN + "+-----------------------------------------------+" + RESET);
    System.out.print(GREEN + "| " + RESET + PURPLE + "请输入初始自由现金流(FCF)" + RESET + ": ");
    double fcf = scanner.nextDouble();
    System.out.println(GREEN + "+-----------------------------------------------+" + RESET);

    return fcf;
  }

  /**
   * 计算DCF估值
   */
  private static DCFValuation calculateDCFValuation(double initialFCF, DCFParameters params) {
    DCFValuation valuation = new DCFValuation();
    double[] projectedFCF = new double[params.getForecastYears()];
    double[] discountedFCF = new double[params.getForecastYears()];

    // 计算预测期的自由现金流
    projectedFCF[0] = initialFCF * (1 + params.getGrowthRate());
    for (int i = 1; i < params.getForecastYears(); i++) {
      projectedFCF[i] = projectedFCF[i - 1] * (1 + params.getGrowthRate());
    }

    // 计算折现后的自由现金流
    double totalPV = 0;
    for (int i = 0; i < params.getForecastYears(); i++) {
      discountedFCF[i] = projectedFCF[i] / Math.pow(1 + params.getDiscountRate(), i + 1);
      totalPV += discountedFCF[i];
    }

    // 计算终值
    double terminalValue = projectedFCF[params.getForecastYears() - 1] * (1 + params.getTerminalGrowthRate()) /
        (params.getDiscountRate() - params.getTerminalGrowthRate());

    // 折现终值
    double discountedTerminalValue = terminalValue / Math.pow(1 + params.getDiscountRate(), params.getForecastYears());

    // 设置估值结果
    valuation.setProjectedFCF(projectedFCF);
    valuation.setDiscountedFCF(discountedFCF);
    valuation.setTerminalValue(terminalValue);
    valuation.setDiscountedTerminalValue(discountedTerminalValue);
    valuation.setTotalPresentValue(totalPV + discountedTerminalValue);

    return valuation;
  }

  /**
   * ANSI颜色代码常量
   */
  private static final String RESET = "\u001B[0m";
  private static final String BOLD = "\u001B[1m";
  private static final String RED = "\u001B[31m";
  private static final String GREEN = "\u001B[32m";
  private static final String YELLOW = "\u001B[33m";
  private static final String BLUE = "\u001B[34m";
  private static final String PURPLE = "\u001B[35m";
  private static final String CYAN = "\u001B[36m";
  private static final String WHITE_BG = "\u001B[47m";

  /**
   * 计算字符串的可视长度（排除ANSI颜色代码）
   */
  private static int getVisualLength(String str) {
    // 移除所有ANSI颜色代码
    String plainText = str.replaceAll("\\u001B\\[[;\\d]*m", "");
    return plainText.length();
  }

  /**
   * 格式化参数行
   */
  private static String formatParamLine(String label, String value) {
    int totalWidth = 45; // 表格内容的总宽度
    // 计算实际可视长度（不包括ANSI颜色代码）
    int labelVisualLength = getVisualLength(label);
    int valueVisualLength = getVisualLength(value);
    int spaces = totalWidth - labelVisualLength - valueVisualLength;

    // 确保至少有一个空格
    if (spaces < 1)
      spaces = 1;

    StringBuilder spacer = new StringBuilder();
    for (int i = 0; i < spaces; i++) {
      spacer.append(" ");
    }
    return YELLOW + "| " + RESET + label + CYAN + value + RESET + spacer.toString() + YELLOW + "|" + RESET;
  }

  /**
   * 格式化现金流行
   */
  private static String formatFCFLine(int year, String fcfValue, String discountedValue) {
    // 计算可视内容长度
    String yearStr = "第" + year + "年: ";
    String middleStr = " (折现值: ";
    String endStr = ")";

    // 构建完整的内容字符串（包含颜色代码）
    String content = yearStr + BOLD + fcfValue + RESET + middleStr + PURPLE + discountedValue + RESET + endStr;

    int totalWidth = 49; // 表格内容的总宽度
    int contentVisualLength = getVisualLength(content);
    int spaces = totalWidth - contentVisualLength;

    // 确保至少有一个空格
    if (spaces < 1)
      spaces = 1;

    StringBuilder spacer = new StringBuilder();
    for (int i = 0; i < spaces; i++) {
      spacer.append(" ");
    }
    return GREEN + "| " + RESET + yearStr +
        BOLD + fcfValue + RESET +
        middleStr + PURPLE + discountedValue + RESET + endStr +
        spacer.toString() + GREEN + "|" + RESET;
  }

  /**
   * 格式化终值行
   */
  private static String formatTerminalLine(String label, String value) {
    int totalWidth = 45; // 表格内容的总宽度
    // 构建完整的内容字符串（包含颜色代码）
    String content = label + BOLD + value + RESET;
    // 计算实际可视长度（不包括ANSI颜色代码）
    int contentVisualLength = getVisualLength(content);
    int spaces = totalWidth - contentVisualLength;

    // 确保至少有一个空格
    if (spaces < 1)
      spaces = 1;

    StringBuilder spacer = new StringBuilder();
    for (int i = 0; i < spaces; i++) {
      spacer.append(" ");
    }
    return BLUE + "| " + RESET + label + BOLD + value + RESET + spacer.toString() + BLUE + "|" + RESET;
  }

  /**
   * 格式化结果行
   */
  private static String formatLine(String label, String value) {
    // 计算需要的空格数以保持右侧边框对齐
    int totalWidth = 45; // 表格内容的总宽度
    // 构建完整的内容字符串（包含颜色代码）
    String content = label + BOLD + value + RESET;
    // 计算实际可视长度（不包括ANSI颜色代码）
    int contentVisualLength = getVisualLength(content);
    int spaces = totalWidth - contentVisualLength;

    // 确保至少有一个空格
    if (spaces < 1)
      spaces = 1;

    StringBuilder spacer = new StringBuilder();
    for (int i = 0; i < spaces; i++) {
      spacer.append(" ");
    }
    return RED + "| " + RESET + label + BOLD + value + RESET + spacer.toString() + RED + "|" + RESET;
  }

  /**
   * 生成估值报告
   */
  private static void generateValuationReport(DCFValuation valuation, DCFParameters params) {
    DecimalFormat df = new DecimalFormat("#,##0.00");

    // 打印分隔线
    String separator = IntStream.range(0, 60).mapToObj(i -> "=").reduce("", (a, b) -> a + b);

    // 标题使用白底蓝字
    System.out.println("\n" + WHITE_BG + BLUE + BOLD + separator + RESET);
    System.out.println(WHITE_BG + BLUE + BOLD + "                DCF估值报告                " + RESET);
    System.out.println(WHITE_BG + BLUE + BOLD + separator + RESET);

    // 参数设置使用黄色
    System.out.println("\n" + YELLOW + BOLD + "【参数设置】" + RESET);
    System.out.println(YELLOW + "+-----------------------------------------------+" + RESET);

    System.out.println(formatParamLine("折现率(WACC): ", (params.getDiscountRate() * 100) + "%"));
    System.out.println(formatParamLine("短期增长率: ", (params.getGrowthRate() * 100) + "%"));
    System.out.println(formatParamLine("永续增长率: ", (params.getTerminalGrowthRate() * 100) + "%"));
    System.out.println(formatParamLine("预测年数: ", params.getForecastYears() + "年"));
    System.out.println(YELLOW + "+-----------------------------------------------+" + RESET);

    // 预测期自由现金流使用绿色
    System.out.println("\n" + GREEN + BOLD + "【预测期自由现金流】" + RESET);
    System.out.println(GREEN + "+---------------------------------------------------+" + RESET);

    for (int i = 0; i < params.getForecastYears(); i++) {
      System.out.println(formatFCFLine(
          i + 1,
          df.format(valuation.getProjectedFCF()[i]),
          df.format(valuation.getDiscountedFCF()[i])));
    }
    System.out.println(GREEN + "+---------------------------------------------------+" + RESET);

    // 终值计算使用蓝色
    System.out.println("\n" + BLUE + BOLD + "【终值计算】" + RESET);
    System.out.println(BLUE + "+-----------------------------------------------+" + RESET);

    System.out.println(formatTerminalLine("终值: ", df.format(valuation.getTerminalValue())));
    System.out.println(formatTerminalLine("折现后终值: ", df.format(valuation.getDiscountedTerminalValue())));
    System.out.println(BLUE + "+-----------------------------------------------+" + RESET);

    // 估值结果使用红色
    System.out.println("\n" + RED + BOLD + "【估值结果】" + RESET);
    System.out.println(RED + "+-----------------------------------------------+" + RESET);

    // 格式化并打印每一行
    double fcfPV = valuation.getTotalPresentValue() - valuation.getDiscountedTerminalValue();
    System.out.println(formatLine("预测期现金流现值: ", df.format(fcfPV)));
    System.out.println(formatLine("终值现值: ", df.format(valuation.getDiscountedTerminalValue())));
    System.out.println(formatLine("企业总价值: ", df.format(valuation.getTotalPresentValue())));
    System.out.println(formatLine("企业价值7折: ", df.format(valuation.getTotalPresentValue() * 0.7)));

    System.out.println(RED + "+-----------------------------------------------+" + RESET);

    // 打印结束分隔线
    System.out.println("\n" + WHITE_BG + BLUE + BOLD + separator + RESET);
  }
}